package com.ruoyi.framework.app.service.impl;

import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.model.WeChatUserInfo;
import com.ruoyi.common.enums.RoleEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.app.service.AppLoginService;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * description: 默认登录业务层接口实现类
 * date: 2023年04月11日 9:13
 * author: tmac-1
 * version: 1.0
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class AppLoginServiceImpl implements AppLoginService {

    private final SysLoginService loginService;
    private final TokenService tokenService;
    private final AuthenticationManager authenticationManager;
    private final ISysConfigService configService;
    private final ISysUserService sysUserService;
    private final SysPermissionService permissionService;

    @Override
    public String login(LoginBody entity) {
        String username = entity.getUsername();
        String password = entity.getPassword();
        // 用户验证
        Authentication authentication = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        loginService.recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

    @Override
    public synchronized String getToken(WeChatUserInfo weChatUserInfo) {
        SysUser user = sysUserService.selectUserByUserName(weChatUserInfo.getUserName());
        if (ObjectUtil.isNull(user)) {
            SysUser sysUserParam = new SysUser();
            sysUserParam.setUserName(weChatUserInfo.getUserName());
            sysUserParam.setNickName(weChatUserInfo.getNickName());
            sysUserParam.setAvatar(weChatUserInfo.getAvatar());
            sysUserParam.setSex(convertSex(weChatUserInfo.getSex()));
            String initPassword = configService.selectConfigByKey("sys.user.initPassword");
            sysUserParam.setPassword(SecurityUtils.encryptPassword(initPassword));
            sysUserParam.setRoleIds(new Long[]{RoleEnum.COMMON.getRoleId()});
            sysUserParam.setCreateBy(weChatUserInfo.getUserName());
            if (StringUtils.isNotBlank(weChatUserInfo.getMobile())) {
                sysUserParam.setPhonenumber(weChatUserInfo.getMobile());
            }
            sysUserParam.setOpenid(weChatUserInfo.getOpenid());
            sysUserParam.setUnionid(weChatUserInfo.getUnionid());
            sysUserService.insertUser(sysUserParam);
            // 生成token
            SysUser sysUser = sysUserService.selectUserByUserName(weChatUserInfo.getUserName());
            LoginUser loginUser = new LoginUser(sysUser, permissionService.getMenuPermission(sysUser));
            return tokenService.createToken(loginUser);
        }
        user.setNickName(weChatUserInfo.getNickName());
        user.setAvatar(weChatUserInfo.getAvatar());
        user.setSex(convertSex(weChatUserInfo.getSex()));
        user.setAvatar(StringUtils.isNotBlank(weChatUserInfo.getAvatar()) ? weChatUserInfo.getAvatar() : user.getAvatar());
        user.setUpdateBy(weChatUserInfo.getUserName());
        if (StringUtils.isNotBlank(weChatUserInfo.getMobile())) {
            user.setPhonenumber(weChatUserInfo.getMobile());
        }
        user.setOpenid(weChatUserInfo.getOpenid());
        user.setUnionid(weChatUserInfo.getUnionid());
        List<SysRole> roleList = user.getRoles();
        Long[] roleIds = roleList.stream().map(SysRole::getRoleId).toArray(Long[]::new);
        user.setRoleIds(roleIds);
        sysUserService.updateUser(user);
        SysUser sysUser = sysUserService.selectUserByUserName(user.getUserName());
        LoginUser loginUser = new LoginUser(sysUser, permissionService.getMenuPermission(sysUser));
        return tokenService.createToken(loginUser);
    }

    /**
     * 性别转换
     *
     * @param sex
     * @return
     */
    public String convertSex(Integer sex) {
        String sexValue = "2";
        if (CompareUtil.compare(sex, 1) == 0) {
            sexValue = "0";
        } else if (CompareUtil.compare(sex, 2) == 0) {
            sexValue = "1";
        }
        return sexValue;
    }
}
